using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using EnvDTE;
using EnvDTE80;


namespace TeamReview.Replay
{
	internal sealed class CodeMemberLink : IReplayLink
	{
		public static CodeMemberLink Instance = new CodeMemberLink();

		private CodeMemberLink(){}

		#region IReplayLink Members

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
		ReplayReceipt IReplayLink.TryShowReplay(WorkItem workItem,  EnvDTE80.DTE2 applicationObject)
		{
			ReplayReceipt receipt = new ReplayReceipt();
			object fileNameObject = workItem.Fields[CONSTANTS.CODE_FILE_FIELD].Value;
			object snippetObject = workItem.Fields[CONSTANTS.CODE_SNIPPET_FIELD].Value;
			object codeMemberObject = workItem.Fields[CONSTANTS.CODE_MEMBER_FIELD].Value;

			if (fileNameObject == null || snippetObject == null || codeMemberObject == null)
			{
				return receipt;
			}

			string fileName = fileNameObject.ToString();
			string snippet = snippetObject.ToString();
			string codeMember = codeMemberObject.ToString();

			if (String.IsNullOrEmpty(fileName) || String.IsNullOrEmpty(codeMember))
			{
				return receipt;
			}

			applicationObject.ExecuteCommand("File.OpenFile", fileName);
			EnvDTE.TextDocument td = (EnvDTE.TextDocument)applicationObject.ActiveDocument.Object("");
			EnvDTE.TextSelection ts = td.Selection;

			EnvDTE.Document doc = (EnvDTE.Document)applicationObject.ActiveDocument;
			FileCodeModel2 codeModel = applicationObject.Application.DTE.ActiveDocument.ProjectItem.FileCodeModel as FileCodeModel2;

		
			CodeElement foundElement = FindElement(codeModel.CodeElements, codeMember);
			if (foundElement != null)
			{
				receipt.ItemWasFound = true;
				receipt.Outcome = "Review Item found by Code Member name. Exact code NOT found within the Code Member body.";


				ts.GotoLine(foundElement.StartPoint.Line, false);
				EnvDTE.EditPoint startPoint = td.CreateEditPoint(ts.ActivePoint);
				ts.GotoLine(foundElement.EndPoint.Line, true);
				EnvDTE.EditPoint endPoint = td.CreateEditPoint(ts.ActivePoint);

				ts.MoveToPoint(startPoint, false);
				ts.MoveToPoint(endPoint, true);

				string selection = td.Selection.Text.Replace("\r", String.Empty).Trim();
				int firstIndex = selection.IndexOf(snippet.Trim());
				if (firstIndex >= 0)
				{
					receipt.Outcome = "Review Item found by Code Member name. Exact code found within the Code Member body.";
				}



			}
			return receipt;
		}

		private CodeElement FindElement(CodeElements elements, string codeMemberName){
			
			if(elements == null){
				return null;
			}
			foreach(CodeElement element in elements)
			{		
				//switch(element.Kind){
				//    case vsCMElement.vsCMElementFunction:
				//    case vsCMElement.vsCMElementProperty:
				//    case vsCMElement.vsCMElementVariable:
				//    case vsCMElement.vsCMElementEvent:
				//    case vsCMElement.vsCMElementClass:
				//    case vsCMElement.vsCMElementInterface:
				//    case vsCMElement.vsCMElementStruct:
				//    case vsCMElement.vsCMElementEnum:

				try
				{
					if (element != null && element.FullName.Equals(codeMemberName, StringComparison.InvariantCulture))
					{
						return element;
					}
					else
					{
						CodeElement childElement = FindElement(element.Children, codeMemberName);
						if (childElement != null)
						{
							return childElement;
						}
					}
				}
				catch { }

				//}
			}
			return null;
		}
		#endregion
	}
}
